package com._21cn.cms.resource.utils;

import com._21cn.framework.utils.FileUtil;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.Part;
import java.io.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipException;

/**
 * 上传助手类
 * 
 * @author chenjh
 */
public class UploadHelper {

	private static final Logger log = LoggerFactory.getLogger(UploadHelper.class);

	private static boolean resin = true;

	private static String unRarCommand = "unrar x -o+ {RARFILE} {OUTPATH}";

	private static String rarInfoCommand = "unrar vb {RARFILE}";

	public static boolean isResin() {
		return resin;
	}

	public static void setResin( boolean resin ) {
		UploadHelper.resin = resin;
	}

	public String getUnRarCommand() {
		return unRarCommand;
	}

	public void setUnRarCommand( String unRarCommand ) {
		UploadHelper.unRarCommand = unRarCommand;
	}

	public String getRarInfoCommand() {
		return rarInfoCommand;
	}

	public void setRarInfoCommand( String rarInfoCommand ) {
		UploadHelper.rarInfoCommand = rarInfoCommand;
	}

	/**
	 * 通过part.getHeader( "content-disposition" )获取文件名
	 * 
	 * @param part
	 * @return
	 */
	public static String getFileName( Part part ) {
		if( part == null )
			return null;

		String str = part.getHeader( "content-disposition" );
		try {
			str = new String( str.getBytes( "iso-8859-1" ), "utf8" );
			log.debug( "upload fileName:" + str );
		}
		catch( Exception e ) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if( StringUtils.isBlank( str ) ) {
			return null;
		}

		return StringUtils.substringBetween( str, "filename=\"", "\"" );
	}

	/**
	 * 通过part获取文件后缀
	 * 
	 * @param part
	 * @return
	 */
	public static String getFileSuffix( Part part ) {
		if( part == null )
			return null;

		String str = part.getHeader( "content-disposition" );
		if( StringUtils.isBlank( str ) ) {
			return null;
		}

		return StringUtils.substring( str, str.lastIndexOf( "." ), str.length() - 1 );
	}

	/**
	 * 将zip或rar文件解压到指定的目录，并获取文件信息列表
	 * 
	 * @param compressedFile
	 * @param tempPath
	 * @return 返回FileUtil.Folder为值得map列表，key为Folder的物理路径
	 */
	public static List<File> decompressFile( File compressedFile, String tempPath ) {
		List<File> result = null;
		File path = new File( tempPath );
		if( !path.exists() )
			path.mkdirs();
		try {
			if( "zip".equalsIgnoreCase( FileUtil.getFileType( compressedFile.getName() ) ) ) {
				ZipFile zipFile = new ZipFile( compressedFile, "gbk" );
				Enumeration<ZipArchiveEntry> zipEnum = zipFile.getEntries();
				ZipArchiveEntry entry = null;
				while( zipEnum.hasMoreElements() ) {
					entry = zipEnum.nextElement();
					log.debug( "decompressing zip file: " + entry.getName() );

					String file = entry.getName();
					file = file.replace( '\\', '/' );

					if( entry.isDirectory() ) {
						File f = new File( tempPath + File.separator + file );
						boolean ret = f.mkdirs();
						log.debug( "create folder: " + tempPath + File.separator + file + ", ret:" + ret );
					}
					else {
						String folderName = "";
						if( file.indexOf( "/" ) != -1 ) {
							folderName = file.substring( 0, file.lastIndexOf( "/" ) );
							File f = new File( tempPath + File.separator + folderName );
							if( !f.exists() ) {
								boolean ret = f.mkdirs();
								log.debug( "create folder 2: " + tempPath + File.separator + folderName + ", ret:" + ret );
							}
						}

						File f = new File( tempPath + File.separator + file );
						boolean ret = f.createNewFile();
						log.debug( "create file: " + tempPath + File.separator + file + ", ret:" + ret );
						InputStream in = zipFile.getInputStream( entry );
						FileOutputStream out = new FileOutputStream( f );

						byte[] buf = new byte[1024];
						int c;
						while( (c = in.read( buf )) != -1 ) {
							out.write( buf, 0, c );
						}
						out.close();
						in.close();
					}
				}
				zipFile.close();
			}
			else if( "rar".equalsIgnoreCase( FileUtil.getFileType( compressedFile.getName() ) ) ) {
				unRar( compressedFile.getAbsolutePath(), tempPath );
			}
			else {
				return result;
			}
			List<File> files = FileUtil.listFiles( tempPath, true );
			if( files != null ) {
				result = new ArrayList<File>( files.size() );
				for( File f : files ) {
					result.add( f );
				}
			}
		}
		catch( FileNotFoundException e1 ) {
			log.error( e1.getMessage() );
		}
		catch( ZipException e1 ) {
			log.error( e1.getMessage() );
		}
		catch( IOException e1 ) {
			log.error( e1.getMessage() );
		}
		return result;
	}

	/**
	 * 将rar文件解压到outPath目录,保留内部的目录结构<br>
	 * <p>
	 * unrar相关用法:<br>
	 * Usage: unrar <command> -<switch 1> -<switch N> <archive> <files...>
	 * <@listfiles...> <path_to_extract\><br>
	 * <Commands><br>
	 * e Extract files to current directory<br>
	 * l[t,b] List archive [technical, bare]<br>
	 * v[t,b] Verbosely list archive [technical,bare]<br>
	 * x Extract files with full path<br>
	 * <Switches><br>
	 * o+ Overwrite existing files<br>
	 * 解压例子:<br>
	 * unrar e -o+ /data/jsp/y.21cn.com/ROOT/test/rar/abc.rar
	 * /data/jsp/y.21cn.com/ROOT/test/rar/<br>
	 * 获取rar包内目录信息例子:<br>
	 * unrar vb /data/jsp/y.21cn.com/ROOT/test/rar/abc.rar<br>
	 * </p>
	 * 
	 * @param rarfile 待解压的rar文件的完整路径
	 * @param outPath 解压到指定的完整路径
	 */
	public static void unRar( String rarfile, String outPath ) throws IOException {
		// 解压
		File base = new File( outPath );
		if( !base.exists() )
			base.mkdirs();
		// replace {RARFILE},{OUTPATH}
		String command = unRarCommand.replaceAll( "\\x7BRARFILE\\x7D", rarfile ).replaceAll( "\\x7BOUTPATH\\x7D", outPath );
		log.debug( command );
		FileUtil.execCommand( command );
	}

	/**
	 * 定义上传的结果类型
	 */
	public enum UploadResultType {
		SUCCESS, FAIL;
	}

}
